/**
 * 实时通信 Store（SignalR 客户端）
 *
 * 目标：以与 Socket.IO 近似的 API 暴露（on/off/once/emit），对上层基本无感替换。
 */
import { defineStore } from 'pinia'
import { ref } from 'vue'
import request from '@/utils/request.js'
import { HubConnectionBuilder, LogLevel } from '@microsoft/signalr'

export const useSocketStore = defineStore('socket', () => {
  // State
  const socket = ref(null) // SignalR HubConnection 实例
  const isConnected = ref(false)
  const connectionStatus = ref('disconnected') // disconnected, connecting, connected, error
  const reconnectAttempts = ref(0)
  const currentJoinedRoomId = ref(null)

  // 事件监听器管理
  const eventListeners = ref(new Map())

  // 读取本地存储中的 accessToken
  const getAccessToken = () => {
    try {
      const tokenDataStr = localStorage.getItem('token')
      const tokenObj = tokenDataStr ? JSON.parse(tokenDataStr) : null
      return tokenObj?.accessToken || localStorage.getItem('accessToken') || ''
    } catch {
      return ''
    }
  }

  // 读取当前登录用户
  const getCurrentUser = () => {
    try {
      const raw = localStorage.getItem('user')
      const user = raw ? JSON.parse(raw) : null
      return user || {}
    } catch {
      return {}
    }
  }

  // 获取当前用户ID
  const getCurrentUserId = () => {
    const user = getCurrentUser()
    return user?.id || user?.Id || user?.userId || user?.uid
  }

  // 构建Hub URL
  const deriveHubUrlFromApiBase = () => {
    try {
      const base = (request?.defaults?.baseURL || '').replace(/\/+$/, '')
      const withoutApi = base.replace(/\/api$/i, '')
      const url = `${withoutApi}/gamehub`
      return url || '/gamehub'
    } catch {
      return '/gamehub'
    }
  }

  // 注册事件监听器
  const on = (event, callback) => {
    if (!eventListeners.value.has(event)) {
      eventListeners.value.set(event, [])
    }
    eventListeners.value.get(event).push(callback)
    
    // 如果socket已连接，立即注册到当前连接
    if (socket.value) {
      try { socket.value.on(event, callback) } catch (_) {}
    }
  }

  // 移除事件监听器
  const off = (event, callback) => {
    if (eventListeners.value.has(event)) {
      const callbacks = eventListeners.value.get(event)
      const index = callbacks.indexOf(callback)
      if (index > -1) {
        callbacks.splice(index, 1)
      }
    }
    
    // 如果socket已连接，立即从当前连接移除
    if (socket.value) {
      try { socket.value.off(event, callback) } catch (_) {}
    }
  }

  // 一次性事件监听器
  const once = (event, callback) => {
    if (!socket.value) {
      return
    }
    const wrapper = (...args) => {
      try { callback(...args) } finally { off(event, wrapper) }
    }
    on(event, wrapper)
  }

  // 建立与 SignalR Hub 的连接
  const connect = async (hubUrl = (import.meta?.env?.VITE_SIGNALR_HUB_URL || deriveHubUrlFromApiBase())) => {
    if (socket.value && isConnected.value) {
      console.log('SignalR已连接，跳过重复连接')
      return
    }

    try {
      connectionStatus.value = 'connecting'
      console.log('🔌 开始连接SignalR...')
      console.log('Hub URL:', hubUrl)
      
      // 检查access token
      const token = getAccessToken()
      console.log('Access Token 存在:', !!token)
      
      // 构建连接
      socket.value = new HubConnectionBuilder()
        .withUrl(hubUrl, {
          accessTokenFactory: () => getAccessToken(),
          skipNegotiation: false,
          withCredentials: false
        })
        .withAutomaticReconnect([0, 1000, 2000, 5000])
        .configureLogging(LogLevel.Information)
        .build()

      // 设置连接事件监听器
      socket.value.onreconnecting(() => {
        connectionStatus.value = 'connecting'
        reconnectAttempts.value++
      })

      socket.value.onreconnected(() => {
        isConnected.value = true
        connectionStatus.value = 'connected'
        reconnectAttempts.value = 0
        // 断线重连后，自动重新加入房间组
        if (currentJoinedRoomId.value) {
          ensureJoinRoomGroup(currentJoinedRoomId.value)
        }
      })

      socket.value.onclose(() => {
        isConnected.value = false
        connectionStatus.value = 'disconnected'
      })

      // 将在连接前通过 on() 收集的监听器补注册到当前连接上
      if (eventListeners.value && eventListeners.value.size > 0) {
        eventListeners.value.forEach((callbacks, event) => {
          if (Array.isArray(callbacks)) {
            callbacks.forEach(cb => {
              try { socket.value.on(event, cb) } catch (_) {}
            })
          }
        })
      }

      // 启动连接
      console.log('🚀 启动SignalR连接...')
      await socket.value.start()
      isConnected.value = true
      connectionStatus.value = 'connected'
      reconnectAttempts.value = 0
      console.log('✅ SignalR连接成功!')
      
      // 连接成功后，如果之前在某个房间，自动重新加入组
      if (currentJoinedRoomId.value) {
        await ensureJoinRoomGroup(currentJoinedRoomId.value)
      }
    } catch (error) {
      console.error('❌ SignalR连接失败:', error)
      connectionStatus.value = 'error'
      throw error
    }
  }

  // 断开连接
  const disconnect = async () => {
    if (socket.value) {
      try { await socket.value.stop() } catch {}
      socket.value = null
    }

    isConnected.value = false
    connectionStatus.value = 'disconnected'
    reconnectAttempts.value = 0
    eventListeners.value.clear()
  }

  // 重新连接
  const reconnect = async () => {
    try {
      console.log('🔄 开始重新连接SignalR...')
      await disconnect()
      await connect()
      console.log('✅ 重新连接成功')
      return true
    } catch (error) {
      console.error('❌ 重新连接失败:', error)
      throw error
    }
  }

  // 获取连接状态
  const getConnectionStatus = () => ({
    isConnected: isConnected.value,
    status: connectionStatus.value,
    reconnectAttempts: reconnectAttempts.value
  })

  // 加入房间
  const joinRoom = async (roomData) => {
    if (!isConnected.value) {
      throw new Error('Socket未连接')
    }
    
    try {
      // 兼容两种调用方式：joinRoom(roomId, playerData) 和 joinRoom({ roomId, ... })
      let roomId, playerData
      if (typeof roomData === 'string') {
        roomId = roomData
        const user = getCurrentUser()
        playerData = {
          id: getCurrentUserId(),
          username: user?.userName || user?.username || user?.UserName || user?.Username || 'Unknown'
        }
      } else {
        roomId = roomData.roomId || roomData.id
        const user = getCurrentUser()
        playerData = {
          id: getCurrentUserId(),
          username: user?.userName || user?.username || user?.UserName || user?.Username || 'Unknown'
        }
      }
      
      await socket.value.invoke('JoinRoom', { roomId, player: playerData })
      currentJoinedRoomId.value = roomId
      console.log('✅ 成功加入房间:', roomId)
    } catch (error) {
      console.error('加入房间失败:', error)
      throw error
    }
  }

  // 离开房间
  const leaveRoom = async (roomId) => {
    if (!isConnected.value) {
      throw new Error('Socket未连接')
    }
    
    try {
      // 兼容两种调用方式：leaveRoom(roomId) 和 leaveRoom({ roomId })
      const actualRoomId = typeof roomId === 'object' ? roomId.roomId : roomId
      const uid = getCurrentUserId()
      
      await socket.value.invoke('LeaveRoom', { 
        roomId: actualRoomId,
        playerId: uid 
      })
      
      if (currentJoinedRoomId.value === actualRoomId) {
        currentJoinedRoomId.value = null
      }
      console.log('✅ 成功离开房间:', actualRoomId)
    } catch (error) {
      console.error('离开房间失败:', error)
      throw error
    }
  }

  // 确保加入房间组
  const ensureJoinRoomGroup = async (roomId) => {
    if (!roomId || !socket.value || !isConnected.value) {
      console.log('❌ 无法加入房间组:', { roomId, hasSocket: !!socket.value, isConnected: isConnected.value })
      return false
    }
    
    try {
      const user = getCurrentUser()
      const uid = getCurrentUserId()
      
      if (!uid) {
        console.log('❌ 用户ID不存在，无法加入房间组')
        return false
      }
      
      const payload = {
        roomId,
        player: { 
          id: uid, 
          username: (user?.userName || user?.username || user?.UserName || user?.Username || 'Unknown') 
        }
      }
      
      console.log('🔗 尝试加入房间组:', payload)
      await socket.value.invoke('JoinRoom', payload)
      currentJoinedRoomId.value = roomId
      console.log('✅ 成功加入房间组:', roomId)
      return true
    } catch (error) {
      console.error('❌ 加入房间组失败:', error)
      return false
    }
  }

  // 创建房间
  const createRoom = async (roomData) => {
    if (!isConnected.value) {
      throw new Error('Socket未连接')
    }
    
    try {
      const user = getCurrentUser()
      const payload = {
        roomName: roomData.roomName,
        maxPlayers: roomData.maxPlayers,
        gameDuration: roomData.gameDuration ?? roomData.gameTime,
        creator: {
          id: user?.id || user?.userId || user?.uid || null,
          username: user?.userName || user?.username || user?.UserName || user?.Username || 'player'
        }
      }
      
      await socket.value.invoke('CreateRoom', payload)
      console.log('✅ 创建房间请求已发送')
    } catch (error) {
      console.error('创建房间失败:', error)
      throw error
    }
  }

  // 进入游戏
  const enterGame = async (roomId) => {
    if (!isConnected.value) {
      throw new Error('Socket未连接')
    }
    
    try {
      await socket.value.invoke('EnterGame', { roomId })
      console.log('🚪 进入游戏请求已发送')
    } catch (error) {
      console.error('进入游戏失败:', error)
      throw error
    }
  }

  // 开始游戏
  const startGame = async (roomId) => {
    if (!isConnected.value) {
      throw new Error('Socket未连接')
    }
    
    try {
      await socket.value.invoke('StartGame', { roomId })
      console.log('✅ 开始游戏请求已发送')
    } catch (error) {
      console.error('开始游戏失败:', error)
      throw error
    }
  }

  // 玩家准备
  const playerReady = async (data) => {
    if (!isConnected.value) {
      throw new Error('Socket未连接')
    }
    
    try {
      // 兼容两种调用方式：playerReady(data) 和 playerReady({ roomId, playerId, isReady })
      let payload
      if (typeof data === 'object' && data.roomId) {
        payload = data
      } else {
        // 如果只传了部分参数，使用当前用户信息补充
        const uid = getCurrentUserId()
        payload = {
          roomId: data.roomId || data,
          playerId: data.playerId || uid,
          isReady: data.isReady !== undefined ? data.isReady : true
        }
      }
      
      await socket.value.invoke('PlayerReady', payload)
      console.log('✅ 玩家准备状态已更新')
    } catch (error) {
      console.error('更新准备状态失败:', error)
      throw error
    }
  }

  // 重置画布
  const resetCanvas = async (roomId) => {
    if (!isConnected.value) {
      throw new Error('Socket未连接')
    }
    
    try {
      await socket.value.invoke('ResetCanvas', { roomId })
      console.log('🔄 重置画布请求已发送')
    } catch (error) {
      console.error('重置画布失败:', error)
      throw error
    }
  }

  // 获取房间状态
  const getRoomStatus = async (roomId) => {
    if (!isConnected.value) {
      throw new Error('Socket未连接')
    }
    
    try {
      await socket.value.invoke('GetRoomStatus', roomId)
      console.log('🏠 获取房间状态请求已发送')
    } catch (error) {
      console.error('获取房间状态失败:', error)
      throw error
    }
  }

  // 设置玩家准备状态
  const setPlayerReady = async (roomId, isReady) => {
    const uid = getCurrentUserId()
    const payload = { playerId: uid, roomId, isReady: !!isReady }
    if (!socket.value || !isConnected.value) return false
    try {
      await socket.value.invoke('PlayerReady', payload)
      return true
    } catch (_) {
      return false
    }
  }

  // 发送绘画动作
  const paintAction = async (payload) => {
    if (!socket.value || !isConnected.value) {
      console.warn('Socket未连接，无法发送绘画动作')
      return false
    }

    try {
      await socket.value.invoke('PaintAction', payload)
      return true
    } catch (error) {
      console.error('发送绘画动作失败:', error)
      return false
    }
  }

  return {
    // 连接状态
    isConnected,
    connectionStatus,
    reconnectAttempts,
    
    // 连接管理
    connect,
    disconnect,
    reconnect,
    getConnectionStatus,
    
    // 房间管理
    joinRoom,
    leaveRoom,
    ensureJoinRoomGroup,
    createRoom,
    
    // 游戏操作
    startGame,
    playerReady,
    resetCanvas,
    getRoomStatus,
    setPlayerReady,
    enterGame,
    
    // 绘画动作
    paintAction,
    
    // 事件监听
    on,
    off,
    once,
    
    // 工具方法
    getCurrentJoinedRoomId: () => currentJoinedRoomId.value
  }
})


